package com.uit.trip_.utils;

import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;

import android.content.Context;
import android.content.res.AssetManager;
import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.ColorFilter;
import android.graphics.ColorMatrix;
import android.graphics.ColorMatrixColorFilter;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.PorterDuff.Mode;
import android.graphics.PorterDuffColorFilter;
import android.util.DisplayMetrics;
import android.util.Log;
import android.widget.ImageView;

/**
 * @author User
 *
 */
/**
 * @author User
 * 
 */
public class ProcessImage {

	private static ProcessImage mInstance;
	private Context mContext;

	/**
	 * @param pContext
	 */
	private ProcessImage(Context pContext) {
		mContext = pContext;
	}

	/**
	 * @param pContext
	 * @return
	 */
	public static ProcessImage getInstance(Context pContext) {
		if (mInstance == null) {
			mInstance = new ProcessImage(pContext);
		}
		return mInstance;
	}

	/**
	 * @param pSrc
	 * @param pExtra
	 * @param pLeft
	 * @param pTop
	 * @param pAlpha
	 * @return
	 */
	public Bitmap combineImages(Bitmap pSrc, Bitmap pExtra, float pLeft,
			float pTop, int pAlpha) {
		Bitmap cs = null;
		int width, height = 0;
		width = pSrc.getWidth();
		height = pSrc.getHeight();
		cs = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
		Canvas comboImage = new Canvas(cs);
		Paint p = new Paint();
		// p.setAlpha(pAlpha);
		comboImage.drawBitmap(pSrc, 0f, 0f, null);
		comboImage.drawBitmap(pExtra, pLeft, pTop, p);
		return cs;
	}

	public Bitmap combineImages(Bitmap pSrc, Bitmap pExtra) {
		Bitmap cs = null;
		int width, height = 0;
		width = pSrc.getWidth();
		height = pSrc.getHeight();
		cs = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
		Canvas comboImage = new Canvas(cs);
		Paint p = new Paint();
		// p.setAlpha(pAlpha);
		comboImage.drawBitmap(pSrc, 0f, 0f, null);
		comboImage.drawBitmap(pExtra, 0f, 0f, p);
		return cs;
	}

	/**
	 * @param pSrc
	 * @param pExtraImage
	 * @param pExtraX
	 * @param pExtraY
	 * @param pExtraWidth
	 * @param pExtraHeight
	 * @param pExtraAlpha
	 * @return
	 */
	public Bitmap processImage(String pSrc, String pExtraImage, int pExtraX,
			int pExtraY, int pExtraWidth, int pExtraHeight, int pExtraAlpha) {
		Bitmap iResult = null;
		Bitmap iExtraImage = null;
		iResult = getBitmapFromFile(pSrc);
		try {
			iExtraImage = getBitmapFromAsset(pExtraImage);
			iExtraImage = Bitmap.createScaledBitmap(iExtraImage, pExtraWidth,
					pExtraHeight, true);
		} catch (IOException e) {
			// TODO Auto-generated catch block
			Log.d("GhostCam", "processImage IOException : " + e.toString());
			e.printStackTrace();
		}
		iResult = combineImages(iResult, iExtraImage, pExtraX, pExtraY,
				pExtraAlpha);
		return iResult;
	}

	/**
	 * @param pSrc
	 * @param pExtraImage
	 * @param pExtraX
	 * @param pExtraY
	 * @param pExtraWidth
	 * @param pExtraHeight
	 * @param pExtraAlpha
	 * @return
	 */
	public Bitmap processImage(Bitmap pSrc, String pExtraImage, int pExtraX,
			int pExtraY, int pExtraWidth, int pExtraHeight, int pExtraAlpha) {
		Bitmap iResult = pSrc;
		Bitmap iExtraImage = null;
		try {
			iExtraImage = getBitmapFromAsset(pExtraImage);
			iExtraImage = Bitmap.createScaledBitmap(iExtraImage, pExtraWidth,
					pExtraHeight, true);
		} catch (IOException e) {
			// TODO Auto-generated catch block
			Log.d("GhostCam", "processImage IOException : " + e.toString());
			e.printStackTrace();
		}
		iResult = combineImages(iResult, iExtraImage, pExtraX, pExtraY,
				pExtraAlpha);
		return iResult;
	}

	/**
	 * @param pSrc
	 * @param pExtraImage
	 * @param pExtraX
	 * @param pExtraY
	 * @param pExtraWidth
	 * @param pExtraHeight
	 * @param pExtraAlpha
	 * @return
	 */
	public Bitmap processImage(Bitmap pSrc, Bitmap pExtraImage, int pExtraX,
			int pExtraY, int pExtraWidth, int pExtraHeight, int pExtraAlpha) {
		Bitmap iResult = pSrc;
		Bitmap iExtraImage = pExtraImage;
		iResult = combineImages(iResult, iExtraImage, pExtraX, pExtraY,
				pExtraAlpha);
		return iResult;
	}

	/**
	 * @param pPath
	 * @return
	 * @throws IOException
	 */
	public Bitmap getBitmapFromAsset(String pPath) throws IOException {
		Bitmap bitMap = null;
		AssetManager assetManager = mContext.getAssets();
		InputStream is;
		try {
			is = assetManager.open(pPath);
			BitmapFactory.Options options = new BitmapFactory.Options();
			options.inPreferredConfig = Config.ARGB_8888;
			options.inPurgeable = true;
			DisplayMetrics dm = mContext.getResources().getDisplayMetrics();
			options.inDensity = dm.densityDpi;
			bitMap = BitmapFactory.decodeStream(is, null, options);
		} catch (Exception e) {
		}
		return bitMap;
	}

	/**
	 * @param pPath
	 * @return
	 */
	public Bitmap getBitmapFromFile(String pPath) {
		FileInputStream in;
		BufferedInputStream buf = null;
		try {
			in = new FileInputStream(pPath);
			buf = new BufferedInputStream(in);
			byte[] bMapArray = new byte[buf.available()];
			buf.read(bMapArray);
			BitmapFactory.Options opts = new BitmapFactory.Options();
			opts.inPreferredConfig = Config.ARGB_8888;
			opts.inPurgeable = true;
			DisplayMetrics dm = mContext.getResources().getDisplayMetrics();
			opts.inDensity = dm.densityDpi;
			Bitmap bitmap = BitmapFactory.decodeByteArray(bMapArray, 0,
					bMapArray.length, opts);
			if (in != null) {
				in.close();
			}
			if (buf != null) {
				buf.close();
				return bitmap;
			}
		} catch (Exception e) {
			Log.e("Error reading file", e.toString());
		}
		return null;
	}

	/**
	 * @param pIv
	 * @return
	 */
	public static Bitmap getBitmapFromImageView(ImageView pIv) {
		ImageView iv = pIv;
		if (iv == null || iv.getWidth() <= 0)
			return null;
		Bitmap bitmap = Bitmap.createBitmap(iv.getWidth(), iv.getHeight(),
				Bitmap.Config.ARGB_8888);
		Canvas canvas = new Canvas(bitmap);
		iv.draw(canvas);
		return bitmap;
	}

	/**
	 * @param src
	 * @param pSaturation
	 * @param pContrast
	 * @return
	 */
	public Bitmap createBitmapWithGrayAndContrast(Bitmap src,
			float pSaturation, double pContrast) {
		return createContrastBitmap(createGrayBitmap(src, pSaturation),
				pContrast);
	}

	/**
	 * @param bmpOriginal
	 * @param pSaturation
	 * @return
	 */
	public Bitmap createGrayBitmap(Bitmap bmpOriginal, float pSaturation) {
		int width, height;
		height = bmpOriginal.getHeight();
		width = bmpOriginal.getWidth();

		Bitmap bmpGrayscale = Bitmap.createBitmap(width, height,
				Bitmap.Config.RGB_565);
		Canvas c = new Canvas(bmpGrayscale);
		Paint paint = new Paint();
		ColorMatrix cm = new ColorMatrix();
		cm.setSaturation(pSaturation);
		ColorMatrixColorFilter f = new ColorMatrixColorFilter(cm);
		paint.setColorFilter(f);
		c.drawBitmap(bmpOriginal, 0, 0, paint);
		return bmpGrayscale;
	}

	/**
	 * @param src
	 * @param value
	 * @return
	 */
	public static Bitmap createContrastBitmap(Bitmap src, float value) {
		float iContrast = value;
		ColorMatrix cm = new ColorMatrix();
		setContrast(cm, iContrast);
		Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
		mPaint.setColorFilter(new ColorMatrixColorFilter(cm));

		int width, height;
		height = src.getHeight();
		width = src.getWidth();

		Bitmap bmpContrast = Bitmap.createBitmap(width, height,
				Bitmap.Config.ARGB_8888);
		Canvas c = new Canvas(bmpContrast);
		c.drawBitmap(src, 0, 0, mPaint);
		return bmpContrast;

	}

	private static void setContrast(ColorMatrix cm, float pContrast) {
		// TODO Auto-generated method stub
		float scale = pContrast + 1.f;
		float translate = (-.5f * scale + .5f) * 255.f;
		cm.set(new float[] { scale, 0, 0, 0, translate, 0, scale, 0, 0,
				translate, 0, 0, scale, 0, translate, 0, 0, 0, 1, 0 });
	}

	/**
	 * @param src
	 * @param value
	 * @return
	 */
	public Bitmap createContrastBitmap(Bitmap src, double value) {
		// image size
		int width = src.getWidth();
		int height = src.getHeight();
		// create output bitmap
		Bitmap bmOut = Bitmap.createBitmap(width, height, src.getConfig());
		// color information
		int A, R, G, B;
		int pixel;
		// get contrast value
		double contrast = Math.pow((100 + value) / 100, 2);

		// scan through all pixels
		for (int x = 0; x < width; ++x) {
			for (int y = 0; y < height; ++y) {
				// get pixel color
				pixel = src.getPixel(x, y);
				A = Color.alpha(pixel);
				// apply filter contrast for every channel R, G, B
				R = Color.red(pixel);
				R = (int) (((((R / 255.0) - 0.5) * contrast) + 0.5) * 255.0);
				if (R < 0) {
					R = 0;
				} else if (R > 255) {
					R = 255;
				}

				G = Color.red(pixel);
				G = (int) (((((G / 255.0) - 0.5) * contrast) + 0.5) * 255.0);
				if (G < 0) {
					G = 0;
				} else if (G > 255) {
					G = 255;
				}

				B = Color.red(pixel);
				B = (int) (((((B / 255.0) - 0.5) * contrast) + 0.5) * 255.0);
				if (B < 0) {
					B = 0;
				} else if (B > 255) {
					B = 255;
				}

				// set new pixel color to output bitmap
				bmOut.setPixel(x, y, Color.argb(A, R, G, B));
			}
		}

		return bmOut;
	}

	/**
	 * @param src
	 * @return
	 */
	public Bitmap transparentBitmap(Bitmap src) {
		Bitmap rv = null;
		if (src == null) {
			return rv;
		}
		int[] pixels = new int[src.getWidth() * src.getHeight()];
		src.getPixels(pixels, 0, src.getWidth(), 0, 0, src.getWidth(),
				src.getHeight());
		int color = src.getPixel(0, 0);
		for (int i = 0; i < pixels.length; i++) {
			if (pixels[i] == color)
				pixels[i] = Color.TRANSPARENT;
		}
		rv = Bitmap.createBitmap(pixels, src.getWidth(), src.getHeight(),
				Config.ARGB_8888);
		return rv;
	}

	/**
	 * @param pBitmap
	 * @param pFilename
	 * @param pFormat
	 * @return
	 */
	public boolean writeBitmapToFile(Bitmap pBitmap, String pFilename,
			String pFormat) {
		boolean rv = false;
		if (pBitmap == null) {
			Log.e("GhostCam", "writeBitmapToFile >>> Failed to find bitmap "
					+ pBitmap);
			return rv;
		}
		// Currently Android only support two formats: PNG and JPEG
		Bitmap.CompressFormat imgFormat;
		if (pFormat.equalsIgnoreCase("png")) {
			imgFormat = Bitmap.CompressFormat.PNG;
		} else if (pFormat.equalsIgnoreCase("jpeg")) {
			imgFormat = Bitmap.CompressFormat.JPEG;
		} else {
			Log.e("GhostCam", "writeBitmapToFile >>> Invalid format " + pFormat);
			return rv;
		}
		try {
			FileOutputStream out = new FileOutputStream(pFilename);
			rv = pBitmap.compress(imgFormat, 70, out);
			out.close();
		} catch (IOException e) {
			Log.e("GhostCam", "Error writing bitmap:" + e.toString());
			return false;
		}
		return rv;
	}

	public Bitmap resizeBitmap(Bitmap input, int destWidth, int destHeight) {
		int srcWidth = input.getWidth();
		int srcHeight = input.getHeight();
		boolean needsResize = false;
		float p;
		if (srcWidth > destWidth || srcHeight > destHeight) {
			needsResize = true;
			if (srcWidth > srcHeight && srcWidth > destWidth) {
				p = (float) destWidth / (float) srcWidth;
				destHeight = (int) (srcHeight * p);
			} else {
				p = (float) destHeight / (float) srcHeight;
				destWidth = (int) (srcWidth * p);
			}
		} else {
			destWidth = srcWidth;
			destHeight = srcHeight;
		}
		if (needsResize) {
			Bitmap output = Bitmap.createScaledBitmap(input, destWidth,
					destHeight, true);

			return output;
		} else {
			return input;
		}
	}

	// Rotate
	public static Bitmap CreateRotateBitmap(Bitmap originalBmp, float angle) {
		Matrix mat = new Matrix();
		mat.preRotate(angle);// /in degree
		return Bitmap.createBitmap(originalBmp, 0, 0, originalBmp.getWidth(),
				originalBmp.getHeight(), mat, true);
	}

	// Opacity
	public static Bitmap createOpacityBitmap(Bitmap bmpOriginal, int opacity) {
		int width, height;
		height = bmpOriginal.getHeight();
		width = bmpOriginal.getWidth();

		Bitmap bitmap = Bitmap.createBitmap(width, height,
				Bitmap.Config.ARGB_8888);
		Canvas c = new Canvas(bitmap);
		Paint paint = new Paint();
		paint.setAlpha(opacity * 255 / 100);
		c.drawBitmap(bmpOriginal, 0, 0, paint);
		return bitmap;
	}

	// Zoom
	public static Bitmap createZoomBitmap(Bitmap bmpOriginal, int width,
			int height) {

		Log.i("duongnx", "width:" + width + " " + height);
		Bitmap bitmap = Bitmap.createBitmap(width, height,
				Bitmap.Config.ARGB_8888);
		Canvas c = new Canvas(bitmap);
		Paint paint = new Paint();
		c.drawBitmap(bmpOriginal, 0, 0, paint);
		return bitmap;
	}

	// BRIGHT
	public static Bitmap createBrightBitmap(Bitmap src, int value) {
		Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
		mPaint.setColorFilter(applyLightness(value));

		int width, height;
		height = src.getHeight();
		width = src.getWidth();

		Bitmap bmpContrast = Bitmap.createBitmap(width, height,
				Bitmap.Config.ARGB_8888);
		Canvas c = new Canvas(bmpContrast);
		c.drawBitmap(src, 0, 0, mPaint);
		return bmpContrast;
	}

	public static PorterDuffColorFilter applyLightness(int progress) {

		if (progress > 0) {
			int value = (int) progress * 255 / 100;
			return new PorterDuffColorFilter(Color.argb(value, 255, 255, 255),
					Mode.SRC_ATOP);
		} else {
			int value = (int) (progress * -1) * 255 / 100;
			return new PorterDuffColorFilter(Color.argb(value, 0, 0, 0),
					Mode.SRC_ATOP);
		}

	}

	// HUE
	public static Bitmap createHueBitmap(Bitmap src, float value) {
		Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
		mPaint.setColorFilter(adjustHue(value));

		int width, height;
		height = src.getHeight();
		width = src.getWidth();

		Bitmap bmpContrast = Bitmap.createBitmap(width, height,
				Bitmap.Config.ARGB_8888);
		Canvas c = new Canvas(bmpContrast);
		c.drawBitmap(src, 0, 0, mPaint);
		return bmpContrast;
	}

	public static ColorFilter adjustHue(float value) {
		ColorMatrix cm = new ColorMatrix();

		adjustHue(cm, value);

		return new ColorMatrixColorFilter(cm);
	}

	public static void adjustHue(ColorMatrix cm, float value) {
		value = cleanValue(value, 180f) / 180f * (float) Math.PI;
		if (value == 0) {
			return;
		}
		float cosVal = (float) Math.cos(value);
		float sinVal = (float) Math.sin(value);
		float lumR = 0.213f;
		float lumG = 0.715f;
		float lumB = 0.072f;
		float[] mat = new float[] {
				lumR + cosVal * (1 - lumR) + sinVal * (-lumR),
				lumG + cosVal * (-lumG) + sinVal * (-lumG),
				lumB + cosVal * (-lumB) + sinVal * (1 - lumB), 0, 0,
				lumR + cosVal * (-lumR) + sinVal * (0.143f),
				lumG + cosVal * (1 - lumG) + sinVal * (0.140f),
				lumB + cosVal * (-lumB) + sinVal * (-0.283f), 0, 0,
				lumR + cosVal * (-lumR) + sinVal * (-(1 - lumR)),
				lumG + cosVal * (-lumG) + sinVal * (lumG),
				lumB + cosVal * (1 - lumB) + sinVal * (lumB), 0, 0, 0f, 0f, 0f,
				1f, 0f, 0f, 0f, 0f, 0f, 1f };
		cm.postConcat(new ColorMatrix(mat));
	}

	protected static float cleanValue(float p_val, float p_limit) {
		return Math.min(p_limit, Math.max(-p_limit, p_val));
	}

	public static Bitmap getBitmapFromURL(String src) {
		try {
			URL url = new URL(src);
			HttpURLConnection connection = (HttpURLConnection) url
					.openConnection();
			connection.setDoInput(true);
			connection.connect();
			InputStream input = connection.getInputStream();
			Bitmap myBitmap = BitmapFactory.decodeStream(input);
			return myBitmap;
		} catch (IOException e) {
			e.printStackTrace();
			return null;
		}
	}
}
